﻿using BCCommon;
using BCCommon.Enums;
using BCCommon.Extensions;
using BCCommon.OAEnums;
using BCCommon.OAEnums.Attendance;
using BCCommon.OAEnums.Workflow;
using BCData.MySql.Admin;
using BCData.MySql.Dictionary;
using BCData.OA.Attendance.AttendanceRemedyApply;
using BCData.OA.Attendance.AttendanceRemedyRules;
using BCData.OA.ApplyOrder;
using BCData.OA.TeamWorks.AttendanceTaskRecord;
using BCData.OA.TeamWorks.TaskReceiverRecord;
using BCData.OA.TeamWorks.TaskRecord;
using BCData.OA.TeamWorks.TaskRejectRecord;
using BCData.OA.Workflow.WorkflowActivityInstanceReference;
using BCDto.FMIS.SOBSetting;
using BCDto.MySql.Admin;
using BCDto.OA.Attendance.AttendanceRemedyApply;
using BCDto.OA.ApplyOrder;
using BCDto.OA.TeamWorks.TaskRecord;
using BCDto.OA.TeamWorks.TaskRejectRecord;
using BCDto.OA.Workflow.WorkflowOperation;
using BCEntity.OA.Attendance.AttendanceRemedyApply;
using BCEntity.OA.ApplyOrder;
using BCEntity.OA.TeamWorks.TaskRecord;
using BCEntity.OA.Workflow.WorkflowActivityInstanceReference;
using BCService.OA.Attendance.AttendanceGroup;
using BCService.Utils;
using BCService.WorkflowEngine;
using System;
using System.Collections.Generic;
using System.Linq;

namespace BCService.OA.ApplyOrder.RemedyCheckInApplyService
{
    /// <summary>
    /// 考勤补卡申请单服务
    /// </summary>
    public class RemedyCheckInApplyOrderService : IRemedyCheckInApplyOrderService
    {
        private readonly IApplyOrderData applyOrderData;
        private readonly ITaskRecordData taskRecordData;
        private readonly IAttendanceRemedyRulesData attendanceRemedyRulesData;
        private readonly IAttendanceGroupService attendanceGroupService;
        private readonly IAttendanceRemedyApplyData attendanceRemedyApplyData;
        private readonly ITaskReceiverRecordData taskReceiverRecordData;
        private readonly ITaskRejectRecordData taskRejectRecordData;
        private readonly IWorkflowEngineService workflowEngineService;
        private readonly IAttendanceTaskRecordData attendanceTaskRecordData;
        private readonly IDictionaryReferenceData dictionaryReferenceData;
        private readonly IAdminData adminData;
        private readonly IWorkflowActivityInstanceReferenceData workflowActivityInstanceReferenceData;

        public RemedyCheckInApplyOrderService(IApplyOrderData applyOrderData,
            ITaskRecordData taskRecordData,
            IAttendanceRemedyRulesData attendanceRemedyRulesData,
            IAttendanceGroupService attendanceGroupService,
            IAttendanceRemedyApplyData attendanceRemedyApplyData,
            ITaskReceiverRecordData taskReceiverRecordData,
            ITaskRejectRecordData taskRejectRecordData,
            IWorkflowEngineService workflowEngineService,
            IAttendanceTaskRecordData attendanceTaskRecordData,
            IDictionaryReferenceData dictionaryReferenceData,
            IWorkflowActivityInstanceReferenceData workflowActivityInstanceReferenceData,
            IAdminData adminData)
        {
            this.applyOrderData = applyOrderData;
            this.taskRecordData = taskRecordData;
            this.attendanceRemedyRulesData = attendanceRemedyRulesData;
            this.attendanceGroupService = attendanceGroupService;
            this.attendanceRemedyApplyData = attendanceRemedyApplyData;
            this.taskReceiverRecordData = taskReceiverRecordData;
            this.taskRejectRecordData = taskRejectRecordData;
            this.workflowEngineService = workflowEngineService;
            this.attendanceTaskRecordData = attendanceTaskRecordData;
            this.dictionaryReferenceData = dictionaryReferenceData;
            this.workflowActivityInstanceReferenceData = workflowActivityInstanceReferenceData;
            this.adminData = adminData;
        }

        #region 创建申请单

        /// <summary>
        /// 创建补卡申请类型的申请单
        /// </summary>
        /// <param name="admin">当前管理员</param>
        /// <param name="dto">申请信息</param>
        /// <param name="sobSetting">账套信息</param>    
        /// <returns></returns>
        public ApplyOrderDto Create(AdminDto admin, ApplyOrderRequestDto dto, SOBSettingDto sobSetting = null)
        {
            string typeStr = ((OAApplyOrderType)Enum.Parse(typeof(OAApplyOrderType), dto.Type.ToString())).GetDescriptionString();
            if (dto.RemedyCheckInApply == null)
            {
                throw new ArgumentException("补卡申请信息不能为空。");
            }
            //校验补卡次数
            var attendanceRemedyRule = attendanceRemedyRulesData.GetFirstDefaultAsync().GetAwaiter().GetResult();
            if (attendanceRemedyRule == null)
            {
                throw new ArgumentException("未设置补卡规则，请联系管理员。");
            }
            //过去天数的申请判断
            DateTime date = DateTime.Now.AddDays(-attendanceRemedyRule.LimitRemedyDays);
            List<AttendanceRemedyApplyEntity> applyRecords = attendanceRemedyApplyData.GetEntitiesAsync(admin.AdminId).GetAwaiter().GetResult().ToList();
            if (applyRecords.Count(s => s.CreateTime >= date && s.CreateTime <= DateTime.Now && s.Status != RemedyApplyStatus.RollBack) > attendanceRemedyRule.LimitRemedyCount)
            {
                throw new ArgumentException("本月申请补卡次数已用完，不能再申请了。");
            }
            //增加考勤补卡申请记录
            string applyCode = RandomCode.GenerateOAApplyCode();
            if (dto.Copiers != null && dto.Copiers.Length > 0)
            {
                foreach (var item in dto.Copiers)
                {
                    var receiverAdmin = adminData.GetAdmin(item);
                    if (receiverAdmin == null)
                    {
                        throw new ArgumentException("抄送人信息不存在");
                    }
                }
            }
            #region 创建申请单信息
            ApplyOrderEntity res = this.MarkApplyOrder(admin, dto, applyCode, typeStr);
            #endregion
            if (res != null)
            {
                #region 创建补卡申请信息
                this.MarkAttendanceRemedyApply(admin, dto, applyCode);
                #endregion

                #region 创建工作流任务信息
                this.MakeTaskOrder(admin, dto, applyCode);
                #endregion

            }
            return res.As<ApplyOrderDto>();
        }

        #endregion

        #region 创建申请单信息
        private ApplyOrderEntity MarkApplyOrder(AdminDto admin, ApplyOrderRequestDto dto, string applyCode, string typeStr)
        {
            ApplyOrderEntity entity = new ApplyOrderEntity
            {
                AdminId = admin.AdminId,
                AdminName = admin.FullName,
                ApplyCode = applyCode,
                DepartmentId = admin.DepartmentId.Value,
                DepartmentName = admin.Department.DepartmentName,
                Type = dto.Type.ToString(),
                CopierIds = dto.Copiers.IsNotNull() ? dto.Copiers.Length > 1 ? string.Join(",", dto.Copiers) : dto.Copiers[0].ToString() : "",
                Title = string.Format("{0}提交的{1}", admin.FullName, typeStr),
                Content = string.Format("缺卡原因:{0}", dto.RemedyCheckInApply.RemedyReason),
                CompanyId = admin.CompanyId
            };
            return applyOrderData.InsertAsync(entity).GetAwaiter().GetResult();
        }



        #endregion

        #region 创建考勤补卡申请信息

        private void MarkAttendanceRemedyApply(AdminDto admin, ApplyOrderRequestDto dto, string applyCode)
        {
            var groupViewInfo = attendanceGroupService.GetCurrentAttendanceGroup(admin);
            if (!groupViewInfo.WorkDayList.Any(s => s.ClassId == dto.RemedyCheckInApply.SelectedClassId))
            {
                throw new ArgumentException("当前员工的考勤班次不存在，请联系管理员");
            }
            AttendanceRemedyApplyEntity remedyApplyEntity = new AttendanceRemedyApplyEntity
            {
                ApplyCode = applyCode,
                AdminId = admin.AdminId,
                AdminName = admin.FullName,
                CompanyId = admin.CompanyId,
                DepartmentId = admin.DepartmentId.Value,
                DepartmentName = admin.Department.DepartmentName,
                RemedyDate = dto.RemedyCheckInApply.RemedyDate.Date,
                RemedyReason = dto.RemedyCheckInApply.RemedyReason,
                RemedyTime = dto.RemedyCheckInApply.RemedyTime,
                RemarkFiles = dto.RemedyCheckInApply.Files.IsNotNull() ? string.Join(",", dto.RemedyCheckInApply.Files) : string.Empty,
                ClassId = dto.RemedyCheckInApply.SelectedClassId,
                WeekDay = string.Format("星期{0}", WeekHelper.GetWeekName(dto.RemedyCheckInApply.RemedyDate.Date.DayOfWeek)),
                AttendanceGroupId = groupViewInfo.GroupInfo.GroupId,
                ClassName = groupViewInfo.WorkDayList.First(s => s.ClassId == dto.RemedyCheckInApply.SelectedClassId).ClassName,
            };
            attendanceRemedyApplyData.InsertAsync(remedyApplyEntity).GetAwaiter().GetResult();
        }

        #endregion

        #region 创建工作流任务信息
        private void MakeTaskOrder(AdminDto admin, ApplyOrderRequestDto dto, string applyCode)
        { //创建任务工作流任务              
            string instanceNo = string.Empty;
            string key = OATaskBusinessType.WorkflowBusiness_RemedyCheckIn_Operations.ToString();
            long instanceId = this.workflowEngineService.InitWorkflowActivityInstance(admin, key, admin.CompanyId, false, RoleType.Admin, ref instanceNo);

            var dictionaryTask = this.dictionaryReferenceData.GetEntityAsync(key).GetAwaiter().GetResult();
            TaskRecordEntity taskRecordEntity = new TaskRecordEntity()
            {
                WorkflowActivityInstanceId = instanceId,
                TaskRecordNo = Guid.NewGuid().ToString(),
                BusinessType = dictionaryTask.SearchKey,
                BusinessTypeName = "考勤补卡申请",
                TaskCategory = OATaskCategoryType.OfficeHead,
                CurrentlyStep = 0,
                TaskExecuterAdminId = admin.AdminId,
                TaskExecuterFullName = admin.FullName,
                HandleStatus = OATaskHandleStatus.Handled,
                CompleteTime = DateTime.Now,
                StartTime = DateTime.Now,
                CompanyId = admin.CompanyId,
                RoleType = RoleType.Admin
            };
            List<TaskReceiverRecordEntity> receivers = new List<TaskReceiverRecordEntity>();
            if (dto.Copiers.IsNotNull())
            {
                foreach (var item in dto.Copiers)
                {
                    var receiverAdmin = adminData.GetAdmin(item);
                    receivers.Add(new TaskReceiverRecordEntity
                    {
                        ReceiverRole = OATaskReceiverRole.Participant,
                        ReceiverAdminId = receiverAdmin.AdminId,
                        ReceiverAdminFullName = receiverAdmin.FullName,
                        TaskStep = 0,
                        CreateTime = DateTime.Now,
                        WorkflowActivityInstanceId = instanceId
                    });
                }
            }
            var task = this.taskRecordData.InsertAsync(taskRecordEntity, receivers).GetAwaiter().GetResult();
            if (task != null)
            {
                WorkflowActivityInstanceReferenceEntity referenceEntity = new WorkflowActivityInstanceReferenceEntity
                {
                    WorkflowActivityInstanceReferenceNo = instanceNo,
                    WorkflowActivityInstanceId = instanceId,
                    WorkflowType = "Attendance",
                    BusinessType = dictionaryTask.Name,
                    ReferenceNo = applyCode,
                    ReferenceType = "System.String"
                };
                this.workflowActivityInstanceReferenceData.Add(referenceEntity).GetAwaiter().GetResult();
                this.workflowEngineService.NextStep(instanceId);
                this.workflowEngineService.Start(instanceId);
            }
        }
        #endregion

        #region 获取详情信息

        /// <summary>
        /// 获取补卡申请类型的申请单详情
        /// </summary>
        /// <param name="admin">当前管理员</param>
        /// <param name="applyOrderId">申请单Id</param>
        /// <returns></returns>
        public ApplyOrderViewDto GetDetail(AdminDto admin, long applyOrderId)
        {
            var applyOrder = applyOrderData.GetById(applyOrderId).GetAwaiter().GetResult();
            if (!applyOrder.IsRead)
            {
                applyOrder = applyOrderData.UpdateApplyOrderRead(applyOrderId, admin.FullName, admin.AdminId).GetAwaiter().GetResult();
            }
            ApplyOrderViewDto view = new ApplyOrderViewDto
            {
                ApplyOrderInfo = applyOrder.As<ApplyOrderDto>(),
                BusinessData = attendanceRemedyApplyData.GetByApplyCodeAsync(applyOrder.ApplyCode).GetAwaiter().GetResult().As<AttendanceRemedyApplyDto>()
            };
            var approvalRecords = taskRecordData.GetTaskRecordEntitiesByReferenceNoAsync(applyOrder.ApplyCode).GetAwaiter().GetResult().As<List<ApplyOrderApprovalRecordDto>>();
            if (approvalRecords.Any())
            {
                view.TaskRecords = approvalRecords.OrderBy(c => c.CreateTime).ToList();
                long workflowActivityInstanceId = approvalRecords.First().WorkflowActivityInstanceId;
                view.Copiers = taskReceiverRecordData.GetByWorkflowActivityInstanceId(workflowActivityInstanceId).GetAwaiter().GetResult().As<List<TaskReceiverRecordDto>>();
                foreach (var item in view.TaskRecords.Where(s => s.HandleStatus == OATaskHandleStatus.Dismissed))
                {
                    item.RejectInfo = taskRejectRecordData.GetByWorkflowActivityInstanceId(workflowActivityInstanceId, item.TaskRecordNo).GetAwaiter().GetResult().As<TaskRejectRecordDto>();
                }
            }
            return view;
        }

        #region 审批同意申请单

        /// <summary>
        /// 审核通过
        /// </summary>
        /// <param name="admin">当前登录人员</param>
        /// <param name="applyOrderId">申请单Id</param>
        /// <returns></returns>
        public ApplyOrderViewDto Pass(AdminDto admin, long applyOrderId)
        {
            var applyOrder = applyOrderData.GetById(applyOrderId).GetAwaiter().GetResult();
            if (applyOrder.Status == OAApplyOrderStatus.Done)
            {
                throw new ArgumentException("申请单已处理完成，不能重复审批。");
            }
            //工作流任务
            var taskRecord = attendanceTaskRecordData.GetByReferenceNoAndTaskExecuterAdminId(applyOrder.ApplyCode, admin.AdminId).GetAwaiter().GetResult().As<TaskRecordDto>();
            if (taskRecord == null)
            {
                throw new ArgumentException("任务单信息不存在或执行人不正确。");
            }
            this.workflowEngineService.Execution(new WorkflowOperationRequestDto { HandleStatus = OATaskHandleOperationStatus.Handled, TaskRecordNo = taskRecord.TaskRecordNo });
            /**  TODO：推送未配置
            if (newTask.HandleStatus == OATaskHandleStatus.Handled)
            {
                //推送给发起人审核              
                pushMessageSendService.PushMessageForStaffApplication(applyRecod.AdminName, applyRecod.AdminId, PushMessageType.AttendanceRemedyCheckInPassed);
                //推送给抄送人
                var copiers = taskReceiverRecordData.GetByWorkflowActivityInstanceId(taskRecord.WorkflowActivityInstanceId).GetAwaiter().GetResult().As<List<TaskReceiverRecordEntity>>();
                if (copiers.Any())
                {               
                pushMessageSendService.PushMessageForStaffApplication(applyRecod.AdminName, applyRecod.AdminId, PushMessageType.AttendanceRemedyCheckInCopiersNotify, copiers.Select(s => s.ReceiverAdminId).ToArray());
                }
            }
            **/
            return this.GetDetail(admin, applyOrder.ApplyOrderId);
        }

        #endregion

        #region 审批拒绝申请单

        /// <summary>
        /// 审核拒绝
        /// </summary>
        /// <param name="admin">当前登录人员</param>
        /// <param name="applyOrderId">申请单Id</param>
        /// <param name="dto">拒绝原因</param>
        /// <returns></returns>
        public ApplyOrderViewDto Rejected(AdminDto admin, long applyOrderId, ApplyOrderRejectRequestDto dto)
        {
            var applyOrder = applyOrderData.GetById(applyOrderId).GetAwaiter().GetResult();
            //工作流任务
            var taskRecord = attendanceTaskRecordData.GetByReferenceNoAndTaskExecuterAdminId(applyOrder.ApplyCode, admin.AdminId).GetAwaiter().GetResult().As<TaskRecordDto>();
            if (taskRecord == null)
            {
                throw new ArgumentException("任务单信息不存在或执行人不正确。");
            }
            this.workflowEngineService.Execution(new WorkflowOperationRequestDto { HandleStatus = OATaskHandleOperationStatus.Rejected, TaskRecordNo = taskRecord.TaskRecordNo, Remark = dto.RejectReason });
            return this.GetDetail(admin, applyOrder.ApplyOrderId);
        }
        #endregion

        #endregion
    }
}
